#include "Serveur.h"


Serveur::Serveur() {
    idRouteur = 0;
    
    ouvrirFichier("./graphe.txt");
    initServeur();
    lancementServeur();
}


void Serveur::initServeur() {
    socketEcoute = socket(AF_INET, SOCK_DGRAM, 0); // Création d'une socket udp 
    
    if (socketEcoute < 0) { // S'il y a une erreur
        cerr << "Impossible de créer le socket en écoute" << endl;
        exit(1);
    }
    
    adresseServeur.sin_family = AF_INET;
    adresseServeur.sin_addr.s_addr = htonl(INADDR_ANY); // Définition automatique de l'adresse du serveur
    adresseServeur.sin_port = htons(PORT_SERVEUR); // Définition du port du serveur
    
    if (bind(socketEcoute, (struct sockaddr *) &adresseServeur, sizeof(adresseServeur)) < 0) { // Liaison de la socket avec le port d'écoute
        cerr << "Impossible de lier le socket en écoute" << endl;
        exit(1);
    }
    
    listen(socketEcoute, TAILLE_FILE_ATTENTE_SERVEUR); // Création d'une file d'attente de taille 10
    
    adresseProcessusPerte.sin_family = AF_INET;
    adresseProcessusPerte.sin_addr.s_addr = inet_addr(ADRESSE_PROCESSUS_PERTE); // Définition automatique de l'adresse du serveur
    adresseProcessusPerte.sin_port = htons(PORT_PROCESSUS_PERTE); // Définition du port du serveur
}


void Serveur::lancementServeur() {
	cout << endl << "Lancement du serveur..." << endl;
	
	while (true) { // Exécution du routeur
        tailleAdresseClient = sizeof(adresseClient);
        
        memset(message, 0x0, TAILLE_MESSAGE); // Remise à zero du message de facon à connaître le délimiteur de fin de chaîne
        
        if (recvfrom(socketEcoute, message, TAILLE_MESSAGE, 0, (struct sockaddr *) &adresseClient, &tailleAdresseClient) < 0) { // Attente de la réception d'un message (bloquante)
            cerr << "Problème de réception du messsage" << endl;
            exit(1);
        }


		int resultat;
		
		resultat = pthread_create(&threadGestionClient, NULL, Serveur::runGestionClient, (void *)this);
		pthread_join (threadGestionClient, NULL);	
        
		if (resultat < 0) {
			printf("\nErreur de création du thread d'envoie de message...\n");
			exit(EXIT_FAILURE);
		} 
	}		
}


void Serveur::envoieAdresseProcessusPerte(struct sockaddr_in adresse){
    char message[TAILLE_MESSAGE];
    memset(message, 0x0, TAILLE_MESSAGE);
    sprintf(message, "%d:%s:%d:", idRouteur ,inet_ntoa(adresse.sin_addr), ntohs(adresse.sin_port));
    
	cout << "Envoie message au Processus de perte: " << message << endl;
    if (sendto(socketEcoute, message, strlen(message) + 1, 0, (struct sockaddr *) &adresseProcessusPerte, sizeof(adresseProcessusPerte)) < 0) { // Envoie du message au client
        cerr << "Émission du message modifié impossible" << endl;
    }
    
}


void Serveur::calculerVoisin(int idRouteur, char *voisin) {
    for (int i = 0; i < nbRouteur; i++) {
		
        if (idRouteur < nbRouteur && graphe[idRouteur][i] > 0) {
			
            sprintf(voisin, "%s%d:%f:",voisin, i, graphe[idRouteur][i]);
			if (adressesClients.find(i) != adressesClients.end()){ //on regarde si on possede l'adresse des voisins
				sprintf(voisin,"%s%s:%d:",voisin ,inet_ntoa(adressesClients[i].sin_addr), ntohs(adressesClients[i].sin_port));
			}
			else 
                sprintf(voisin, "%s-1:-1:",voisin);
        }
    }
}


void Serveur::gestionClient(){
    char voisin[TAILLE_MESSAGE];
	
	cout << endl << "________________________________________" << endl;
    
	if (strlen(message)) { // Si le message n'est pas vide
		cout << endl << "Reception d'un message depuis " << inet_ntoa(adresseClient.sin_addr) << ":" << ntohs(adresseClient.sin_port) << endl;
		cout << "  Message reçu : " << endl << message << endl;
		
		if (atoi(strtok(message, "\n")) == TYPE_PAQUET_INIT){
			
			memset(message, 0x0, TAILLE_MESSAGE); 
			calculerVoisin(idRouteur, voisin);
			
			sprintf(message, "%d\n%d:%d:%s", TYPE_PAQUET_INIT, idRouteur, nbRouteur,voisin); 
			cout << endl << "Message a envoyer : " << message << endl;
			
			if (sendto(socketEcoute, message, strlen(message) + 1, 0, (struct sockaddr *) &adresseClient, sizeof(adresseClient)) < 0) { // Envoie du message au client
				cerr << "Émission du message modifié impossible" << endl;
			}
            
			this->adressesClients[idRouteur] = adresseClient;
            this->envoieAdresseProcessusPerte(adresseClient);
			
			
		}
	}
	cout << endl << "________________________________________" << endl;
    
	for (int i = 0; i < nbRouteur; i++) {
		if(graphe[i][idRouteur] > 0 && this->adressesClients.find(i) != this->adressesClients.end()){
            
			memset(message, 0x0, TAILLE_MESSAGE); 
			memset(voisin, 0x0, TAILLE_MESSAGE); 
			
			calculerVoisin(i,voisin);
            
			sprintf(message, "%d\n%d:%d:%s", TYPE_PAQUET_INIT, i, nbRouteur,voisin); 
			
			if (sendto(socketEcoute, message, strlen(message) + 1, 0, (struct sockaddr *) &this->adressesClients[i], sizeof(this->adressesClients[i])) < 0) { // Envoie du message au client
				cerr << "Émission du message modifié impossible" << endl;
			}
		}
	}
	idRouteur++;
}


void Serveur::ouvrirFichier(string url) {
    
    int cpt_ligne = 0; //compteur de ligne
    int cpt_bloc_ligne = 0; //compte permettant de compter 4 lignes
    int cpt_sommet = 0;
    
    string ligne;
    ifstream fichier;
    fichier.open(url.c_str());
    
    if(fichier)
    {
        getline(fichier, ligne); 
        
        int nbSommet = atoi(ligne.c_str()); 
        nbRouteur = nbSommet;
        vector<int> degresSommet(nbSommet);
        map<int,Point> coordonnesSommet;
        
        graphe = new float * [nbSommet];
        for (int i=0; i < nbSommet; i++) {
            graphe[i] = new float [nbSommet];
        }
        
        for (int i=0; i < nbSommet; i++) {
            for (int j=0; j < nbSommet; j++) {
                graphe[i][j] = 0.0;
            }
        }
        
        while(fichier && cpt_ligne < nbSommet*4)    //Construction du tableau de degres 
        {               
            cpt_bloc_ligne++;
            cpt_ligne++;
            float x,y;
            getline(fichier, ligne); 
            
            if (cpt_bloc_ligne == 2)
                degresSommet.at(cpt_sommet) = atoi(ligne.c_str());
            if (cpt_bloc_ligne == 3)
                x = atof(ligne.c_str());
            if (cpt_bloc_ligne == 4)
                y = atof(ligne.c_str());
            if (cpt_bloc_ligne == 4){
                cpt_bloc_ligne = 0;
                cpt_sommet++;
            }
			coordonnesSommet[cpt_sommet] = *new Point(x,y);
        }
        
        cpt_sommet = 0;
        cpt_bloc_ligne = 0;
        int cpt_degres = 0;
        int voisin;
        float voisin_x;
        float voisin_y;
        
        while (fichier && cpt_sommet < nbSommet) {
            
            cpt_bloc_ligne++;
            cpt_ligne++;
            
            getline(fichier, ligne); 
            
            if (cpt_degres == 0) {
                if (cpt_bloc_ligne == 2)
                    voisin = atoi(ligne.c_str());
                if (cpt_bloc_ligne == 4){
                    voisin_x = atof(ligne.c_str());
                }
                if (cpt_bloc_ligne == 5){
                    voisin_y = atof(ligne.c_str());
                    cpt_bloc_ligne = 0;
                    cpt_degres++;
//					float dist = sqrt(pow(coordonnesSommet[cpt_sommet].x - coordonnesSommet[voisin].x,2.0)+pow(coordonnesSommet[cpt_sommet].y-coordonnesSommet[voisin].y,2.0));
//                    graphe[cpt_sommet][voisin] = (int)fabs(dist*1000.0);
					graphe[cpt_sommet][voisin] = 1;

                }
            }
            else {
                if (cpt_bloc_ligne == 1)
                    voisin = atoi(ligne.c_str());
                if (cpt_bloc_ligne == 3)
                    voisin_x = atof(ligne.c_str());
                if (cpt_bloc_ligne == 4){
                    voisin_y = atof(ligne.c_str());
                    cpt_bloc_ligne = 0;
                    cpt_degres++;
//					float dist = sqrt(pow(coordonnesSommet[cpt_sommet].x - coordonnesSommet[voisin].x,2.0)+pow(coordonnesSommet[cpt_sommet].y-coordonnesSommet[voisin].y,2.0));
//                    graphe[cpt_sommet][voisin] = (int)fabs(dist*1000.0);
					graphe[cpt_sommet][voisin] = 1;
                }
            }
            if (degresSommet[cpt_sommet] == cpt_degres) {
                cpt_degres = 0;
                cpt_sommet++;
            }                       
        }
        for (int i =0; i < nbSommet; i++) {
            for (int j=0; j<nbSommet; j++) {
                cout << graphe[i][j] << " " ;
            }
            cout << endl;
        }
    }
    else {
        cout << "ERREUR: Impossible d'ouvrir le fichier en lecture." << endl;
    }
    
    fichier.close();
}


void* Serveur::runGestionClient(void *arg){
	Serveur * serv = (Serveur *) arg;
	serv->gestionClient();

    return NULL;
}